package com.project.generation;

import com.project.database.DataBaseData;
import com.project.database.TableData;
import com.project.model.ColumnData;
import com.project.util.Config;
import com.project.util.IoUtil;
import com.project.util.Util;
import lombok.SneakyThrows;

import java.io.File;
import java.net.URI;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;

public class JavaGeneration {

    private Config config;
    private DataBaseData dataBaseData;
    private String controller;
    private String model;
    private String mapper;
    private String mapperXml;
    private String service;
    private String serviceImpl;
    private String javaBasicPath;

    public JavaGeneration(Config config, DataBaseData dataBaseData) {
        this.config = config;
        this.dataBaseData = dataBaseData;
    }

    public void start() {
        this.catalogGeneration();
        List<TableData> tables = this.dataBaseData.getTables();
        for (TableData table : tables) {
            this.controllerGeneration(table);
            this.serviceGeneration(table);
            this.serviceImplGeneration(table);
            this.mapperGeneration(table);
            this.mapperXmlGeneration(table);
            this.modelGeneration(table);
        }
        this.templateGeneration();
    }

    @SneakyThrows
    private void templateGeneration() {
        // 获取controller模板字符串
        URI javaTemplateURL = this.getClass().getClassLoader().getResource("template-java/template").toURI();
        File file = new File(javaTemplateURL);
        IoUtil.fileTransfer(file, this.javaBasicPath);
    }

    @SneakyThrows
    private void mapperXmlGeneration(TableData tableData) {
        // 获取controller模板字符串
        URI javaTemplateURL = this.getClass().getClassLoader().getResource("template-java/template-mapper.xml").toURI();
        File file = new File(javaTemplateURL);
        String javaTemplate = IoUtil.readFile(file);

        // 处理路径
        String modelPath = this.config.getModelPath().replaceAll(Matcher.quoteReplacement("\\"), ".");
        String mapperPath = this.config.getMapperPath().replaceAll(Matcher.quoteReplacement("\\"), ".");

        // java类型名
        String type = Util.firstCharBigLetter(tableData.getTableName());
        // 字段列表
        StringBuilder fields  = new StringBuilder();
        StringBuilder queryCondition  = new StringBuilder();
        StringBuilder insertCondition  = new StringBuilder();
        StringBuilder updateCondition  = new StringBuilder();
        List<String> tableFiled = tableData.getTableFiledList();

        for (int i = 0; i < tableFiled.size(); i++) {
            String cn = tableFiled.get(i);
            fields.append("`"+cn+"`"+(i==tableFiled.size()-1?"":","));
            queryCondition.append("<if test=\"map."+cn+" != null\"> and `"+cn+"`=\\$\\{map."+cn+"} </if>");
            insertCondition.append("<if test=\"item."+cn+" != null\"> \\$\\{item."+cn+"}"+(i==tableFiled.size()-1?"":",")+" </if>");
            insertCondition.append("<if test=\"item."+cn+" == null\"> default"+(i==tableFiled.size()-1?"":",")+" </if>");
            updateCondition.append("<if test=\"data."+cn+" != null\"> `"+cn+"` = \\$\\{data."+cn+"}"+(i==tableFiled.size()-1?"":",")+" </if>");
        }

        // 替换字符串
        javaTemplate = javaTemplate.replaceAll(Util.getTemplateString("mapperPath"), mapperPath);
        javaTemplate = javaTemplate.replaceAll(Util.getTemplateString("modelPath"), modelPath);
        javaTemplate = javaTemplate.replaceAll(Util.getTemplateString("type"), type);
        javaTemplate = javaTemplate.replaceAll(Util.getTemplateString("tableName"), tableData.getTableName());
        javaTemplate = javaTemplate.replaceAll(Util.getTemplateString("tablePrimaryKey"), tableData.getPrimaryKey());
        javaTemplate = javaTemplate.replaceAll(Util.getTemplateString("queryCondition"), queryCondition.toString());
        javaTemplate = javaTemplate.replaceAll(Util.getTemplateString("insertCondition"), insertCondition.toString());
        javaTemplate = javaTemplate.replaceAll(Util.getTemplateString("updateCondition"), updateCondition.toString());
        javaTemplate = javaTemplate.replaceAll(Util.getTemplateString("fields"), fields.toString());

        // 写入文件
        String name = Util.firstCharBigLetter(tableData.getTableName())+"Mapper.xml";
        String endPath = this.mapperXml+"\\"+name;
        IoUtil.write(javaTemplate, endPath);
    }

    @SneakyThrows
    private void mapperGeneration(TableData tableData) {
        // 获取controller模板字符串
        URI javaTemplateURL = this.getClass().getClassLoader().getResource("template-java/template-mapper.java").toURI();
        File file = new File(javaTemplateURL);
        String javaTemplate = IoUtil.readFile(file);

        // 处理路径
        String modelPath = this.config.getModelPath().replaceAll(Matcher.quoteReplacement("\\"), ".");
        String mapperPath = this.config.getMapperPath().replaceAll(Matcher.quoteReplacement("\\"), ".");

        // java类型名
        String type = Util.firstCharBigLetter(tableData.getTableName());
        // 需导入
        StringBuilder imports = new StringBuilder();
        // 表主键类型
        Map<String, ColumnData> tableFiled = tableData.getTableFiled();
        ColumnData columnData = tableFiled.get(tableData.getPrimaryKey());
        String tablePrimaryKeyType = Util.mySqlTypeToJavaType(columnData.getColumnType()).getName();
        imports.append("import "+tablePrimaryKeyType+";\n");
        tablePrimaryKeyType = tablePrimaryKeyType.substring(tablePrimaryKeyType.lastIndexOf(".")+1);

        // 替换字符串
        javaTemplate = javaTemplate.replaceAll(Util.getTemplateString("mapperPath"), mapperPath);
        javaTemplate = javaTemplate.replaceAll(Util.getTemplateString("modelPath"), modelPath);
        javaTemplate = javaTemplate.replaceAll(Util.getTemplateString("type"), type);
        javaTemplate = javaTemplate.replaceAll(Util.getTemplateString("tablePrimaryKeyType"), tablePrimaryKeyType);
        javaTemplate = javaTemplate.replaceAll(Util.getTemplateString("imports"), imports.toString());


        // 写入文件
        String name = Util.firstCharBigLetter(tableData.getTableName())+"Mapper.java";
        String endPath = this.mapper+"\\"+name;
        IoUtil.write(javaTemplate, endPath);
    }

    @SneakyThrows
    private void modelGeneration(TableData tableData) {
        // 获取controller模板字符串
        URI javaTemplateURL = this.getClass().getClassLoader().getResource("template-java/template-model.java").toURI();
        File file = new File(javaTemplateURL);
        String javaTemplate = IoUtil.readFile(file);

        // 处理路径
        String modelPath = this.config.getModelPath().replaceAll(Matcher.quoteReplacement("\\"), ".");

        // java类型名
        String type = Util.firstCharBigLetter(tableData.getTableName());

        // 替换字符串
        javaTemplate = javaTemplate.replaceAll(Util.getTemplateString("modelPath"), modelPath);
        javaTemplate = javaTemplate.replaceAll(Util.getTemplateString("type"), type);

        StringBuilder imports = new StringBuilder();
        Set<String> set = new HashSet<>();
        StringBuilder fields = new StringBuilder();

        Map<String, ColumnData> tableFiled = tableData.getTableFiled();

        for ( String columnName : tableFiled.keySet() ) {
            ColumnData columnData = tableFiled.get(columnName);
            Class c = Util.mySqlTypeToJavaType(columnData.getColumnType());
            String name = c.getName();
            String t = "import "+name+";\n";
            if ( !set.contains(t) ){
                set.add(t);
                imports.append(t);
            }
            String field = name.substring(name.lastIndexOf(".")+1);
            fields.append("\t"+field+" "+columnName+";\n");
        }

        // 替换字符串
        javaTemplate = javaTemplate.replaceAll(Util.getTemplateString("imports"), imports.toString());
        javaTemplate = javaTemplate.replaceAll(Util.getTemplateString("fields"), fields.toString());

        // 写入文件
        String name = Util.firstCharBigLetter(tableData.getTableName())+".java";
        String endPath = this.model+"\\"+name;
        IoUtil.write(javaTemplate, endPath);
    }

    @SneakyThrows
    private void serviceGeneration(TableData tableData) {
        // 获取controller模板字符串
        URI javaTemplateURL = this.getClass().getClassLoader().getResource("template-java/template-service.java").toURI();
        File file = new File(javaTemplateURL);
        String javaTemplate = IoUtil.readFile(file);

        // 处理路径
        String modelPath = this.config.getModelPath().replaceAll(Matcher.quoteReplacement("\\"), ".");
        String servicePath = this.config.getServicePath().replaceAll(Matcher.quoteReplacement("\\"), ".");

        // java类型名
        String type = Util.firstCharBigLetter(tableData.getTableName());
        // 需导入
        StringBuilder imports = new StringBuilder();
        // 表主键类型
        Map<String, ColumnData> tableFiled = tableData.getTableFiled();
        ColumnData columnData = tableFiled.get(tableData.getPrimaryKey());
        String tablePrimaryKeyType = Util.mySqlTypeToJavaType(columnData.getColumnType()).getName();
        imports.append("import "+tablePrimaryKeyType+";\n");
        tablePrimaryKeyType = tablePrimaryKeyType.substring(tablePrimaryKeyType.lastIndexOf(".")+1);

        // 替换字符串
        javaTemplate = javaTemplate.replaceAll(Util.getTemplateString("servicePath"), servicePath);
        javaTemplate = javaTemplate.replaceAll(Util.getTemplateString("modelPath"), modelPath);
        javaTemplate = javaTemplate.replaceAll(Util.getTemplateString("type"), type);
        javaTemplate = javaTemplate.replaceAll(Util.getTemplateString("tablePrimaryKeyType"), tablePrimaryKeyType);
        javaTemplate = javaTemplate.replaceAll(Util.getTemplateString("imports"), imports.toString());


        // 写入文件
        String name = Util.firstCharBigLetter(tableData.getTableName())+"Service.java";
        String endPath = this.service+"\\"+name;
        IoUtil.write(javaTemplate, endPath);
    }

    @SneakyThrows
    private void serviceImplGeneration(TableData tableData) {
        // 获取controller模板字符串
        URI javaTemplateURL = this.getClass().getClassLoader().getResource("template-java/template-serviceImpl.java").toURI();
        File file = new File(javaTemplateURL);
        String javaTemplate = IoUtil.readFile(file);

        // 处理路径
        String modelPath = this.config.getModelPath().replaceAll(Matcher.quoteReplacement("\\"), ".");
        String servicePath = this.config.getServicePath().replaceAll(Matcher.quoteReplacement("\\"), ".");
        String mapperPath = this.config.getMapperPath().replaceAll(Matcher.quoteReplacement("\\"), ".");
        String serviceImplPath = this.config.getServiceImplPath().replaceAll(Matcher.quoteReplacement("\\"), ".");

        // java类型名
        String type = Util.firstCharBigLetter(tableData.getTableName());
        // 需导入
        StringBuilder imports = new StringBuilder();
        // 表主键类型
        Map<String, ColumnData> tableFiled = tableData.getTableFiled();
        ColumnData columnData = tableFiled.get(tableData.getPrimaryKey());
        String tablePrimaryKeyType = Util.mySqlTypeToJavaType(columnData.getColumnType()).getName();
        imports.append("import "+tablePrimaryKeyType+";\n");
        tablePrimaryKeyType = tablePrimaryKeyType.substring(tablePrimaryKeyType.lastIndexOf(".")+1);

        // 替换字符串
        javaTemplate = javaTemplate.replaceAll(Util.getTemplateString("servicePath"), servicePath);
        javaTemplate = javaTemplate.replaceAll(Util.getTemplateString("serviceImplPath"), serviceImplPath);
        javaTemplate = javaTemplate.replaceAll(Util.getTemplateString("mapperPath"), mapperPath);
        javaTemplate = javaTemplate.replaceAll(Util.getTemplateString("modelPath"), modelPath);
        javaTemplate = javaTemplate.replaceAll(Util.getTemplateString("type"), type);
        javaTemplate = javaTemplate.replaceAll(Util.getTemplateString("tablePrimaryKeyType"), tablePrimaryKeyType);
        javaTemplate = javaTemplate.replaceAll(Util.getTemplateString("imports"), imports.toString());


        // 写入文件
        String name = Util.firstCharBigLetter(tableData.getTableName())+"ServiceImpl.java";
        String endPath = this.serviceImpl+"\\"+name;
        IoUtil.write(javaTemplate, endPath);
    }

    @SneakyThrows
    private void controllerGeneration(TableData tableData) {
        // 获取controller模板字符串
        URI javaTemplateURL = this.getClass().getClassLoader().getResource("template-java/template-controller.java").toURI();
        File file = new File(javaTemplateURL);
        String javaTemplate = IoUtil.readFile(file);

        // 处理路径
        String controllerPath = this.config.getControllerPath().replaceAll(Matcher.quoteReplacement("\\"), ".");
        String modelPath = this.config.getModelPath().replaceAll(Matcher.quoteReplacement("\\"), ".");
        String servicePath = this.config.getServicePath().replaceAll(Matcher.quoteReplacement("\\"), ".");

        // java类型名
        String type = tableData.getTableName().substring(0,1).toUpperCase()+tableData.getTableName().substring(1);
        // 需导入
        StringBuilder imports = new StringBuilder();
        // 表主键类型
        Map<String, ColumnData> tableFiled = tableData.getTableFiled();
        ColumnData columnData = tableFiled.get(tableData.getPrimaryKey());
        String tablePrimaryKeyType = Util.mySqlTypeToJavaType(columnData.getColumnType()).getName();
        imports.append("import "+tablePrimaryKeyType+";\n");
        tablePrimaryKeyType = tablePrimaryKeyType.substring(tablePrimaryKeyType.lastIndexOf(".")+1);

        // 替换字符串
        javaTemplate = javaTemplate.replaceAll(Util.getTemplateString("controllerPath"), controllerPath);
        javaTemplate = javaTemplate.replaceAll(Util.getTemplateString("modelPath"), modelPath);
        javaTemplate = javaTemplate.replaceAll(Util.getTemplateString("servicePath"), servicePath);
        javaTemplate = javaTemplate.replaceAll(Util.getTemplateString("tableName"), tableData.getTableName());
        javaTemplate = javaTemplate.replaceAll(Util.getTemplateString("type"), type);
        javaTemplate = javaTemplate.replaceAll(Util.getTemplateString("tablePrimaryKeyType"), tablePrimaryKeyType);
        javaTemplate = javaTemplate.replaceAll(Util.getTemplateString("imports"), imports.toString());

        // 写入文件
        String name = Util.firstCharBigLetter(tableData.getTableName())+"Controller.java";
        String endPath = this.controller+"\\"+name;
        IoUtil.write(javaTemplate, endPath);
    }

    private void catalogGeneration() {
        String basic = config.getOutPath() + File.separator + config.getProjectName() + File.separator + config.getJavaPath();
        this.controller = basic + File.separator + config.getControllerPath();
        this.model = basic + File.separator + config.getModelPath();
        this.mapper = basic + File.separator + config.getMapperPath();
        this.mapperXml = basic + File.separator + config.getMapperXmlPath();
        this.service = basic + File.separator + config.getServicePath();
        this.serviceImpl = basic + File.separator + config.getServiceImplPath();
        this.javaBasicPath = basic + File.separator + config.getJavaBasicPath();

        IoUtil.createPath(controller);
        IoUtil.createPath(model);
        IoUtil.createPath(mapper);
        IoUtil.createPath(mapperXml);
        IoUtil.createPath(service);
        IoUtil.createPath(serviceImpl);
        IoUtil.createPath(javaBasicPath);
    }

}
